home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 49 / Amiga Format CD49 (2000-01-17)(Future Publishing)(GB)(Track 1 of 3)[!][issue 2000-02].iso / +system+ / tools / sound / ahi / developer / devloper.lzx / drivers / toccata / toccata.c < prev    next >
C/C++ Source or Header  |  1979-04-21  |  20KB  |  753 lines

  1.  
  2. #include <exec/exec.h>
  3.  
  4. #include <devices/ahi.h>
  5. #include <libraries/ahi_sub.h>
  6. #include <libraries/toccata.h>
  7.  
  8. #include <dos/dos.h>
  9. #include <dos/dostags.h>
  10.  
  11. #include <proto/exec.h>
  12. #include <proto/dos.h>
  13. #include <proto/intuition.h>
  14. #include <proto/utility.h>
  15. #include <proto/ahi_sub.h>
  16. #include <clib/toccata_protos.h>
  17. #include <pragmas/toccata_pragmas.h>
  18.  
  19. #include <math.h>
  20.  
  21. #include "toccata.h"
  22.  
  23. extern void KPrintF(char *fmt,...);
  24.  
  25. #define dd ((struct toccata *) AudioCtrl->ahiac_DriverData)
  26.  
  27. #define PLAYBUFFERSIZE 512        // Size in bytes
  28. #define RECBUFFERSIZE  512*32     // in bytes
  29.  
  30. extern char __far _LibID[];
  31. extern char __far _LibName[];
  32.  
  33. extern void __asm SlaveProcessEntry(void);
  34. extern void __asm CallPlayFunc(void);
  35. extern void __asm RecordFunc(void);
  36. extern void __asm PlayFuncMono(void);
  37. extern void __asm PlayFuncStereo(void);
  38. extern void __asm PlayFuncMono32(void);
  39. extern void __asm PlayFuncStereo32(void);
  40. extern void __asm MixFunc(void);
  41.  
  42. struct Library        *UtilityBase = NULL;
  43. struct Library        *AHIsubBase  = NULL;
  44. struct ToccataBase    *ToccataBase = NULL;
  45. struct DosLibrary     *DOSBase     = NULL;
  46.  
  47. LONG INPUTS  = 5;
  48. BOOL In_Use  = FALSE;
  49. BOOL NoTask  = FALSE;
  50. LONG IrqSize = 512;
  51.  
  52. LONG fixed2negdbvalue( LONG volume);
  53. LONG fixed2posdbvalue( LONG volume);
  54. BOOL StartPlaying(struct AHIAudioCtrlDrv *AudioCtrl, struct Process *me);
  55. BOOL StartRecording(struct AHIAudioCtrlDrv *AudioCtrl, struct Process *me);
  56.  
  57.  
  58.  
  59. const static STRPTR Inputs[] =
  60. {
  61.   "Line",
  62.   "Aux1",
  63.   "Mic",
  64.   "Mic +20 dB",
  65.   "Mixer"
  66. };
  67.  
  68. const static ULONG inputmap[] =
  69. {
  70.   TINPUT_Line,
  71.   TINPUT_Aux1,
  72.   TINPUT_Mic,
  73.   TINPUT_Mic,
  74.   TINPUT_Mix
  75. };
  76.  
  77. const static ULONG micgainmap[] =
  78. {
  79.   FALSE,
  80.   FALSE,
  81.   FALSE,
  82.   TRUE,
  83.   FALSE
  84. };
  85.  
  86.  
  87. int  __saveds __asm __UserLibInit (register __a6 struct Library *libbase)
  88. {
  89.   char prefs[10]="0";
  90.  
  91.   AHIsubBase = libbase;
  92.  
  93.   if(!(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",37)))
  94.   {
  95.     Alert(AN_Unknown|AG_OpenLib|AO_DOSLib);
  96.     return 1;
  97.   }
  98.  
  99.   if(!(UtilityBase = OpenLibrary("utility.library",37)))
  100.   {
  101.     Alert(AN_Unknown|AG_OpenLib|AO_UtilityLib);
  102.     return 1;
  103.   }
  104.  
  105. /*
  106. ** "toccata..library" is a modified version of "toccata.library" which calls
  107. ** TT_RawInt in a real hardware interrupt instead of a software interrupt.
  108. ** The author wishes to remain anonymous, but his hack suits my purposes well.
  109. */
  110.  
  111.   ToccataBase = (struct ToccataBase *)OpenLibrary("toccata..library",12);
  112.  
  113.   if(ToccataBase == NULL)
  114.   {
  115.     ToccataBase = (struct ToccataBase *)OpenLibrary("toccata.library",12);
  116.   }
  117.  
  118.   if(ToccataBase == NULL)
  119.   {
  120.     struct IntuitionBase *IntuitionBase = (struct IntuitionBase *)
  121.         OpenLibrary("intuition.library", 37);
  122.     struct EasyStruct req = { sizeof (struct EasyStruct),
  123.         0, _LibName, "Cannot open 'toccata.library' v12", "OK"};
  124.  
  125.     if(IntuitionBase) {
  126.           EasyRequest( NULL, &req, NULL, NULL );
  127.           CloseLibrary((struct Library *) IntuitionBase);
  128.     }
  129.     else
  130.     {
  131.       Alert(AN_Unknown|AG_OpenLib|AO_Unknown);
  132.     }
  133.     // NOTE! Don't fail if Toccata.library couldn't be opened!
  134.   }
  135.  
  136.  
  137.   /* Check for DraCoMotion */
  138.  
  139.   if(ToccataBase &&
  140.      ToccataBase->tb_HardInfo &&
  141.     (ToccataBase->tb_HardInfo->hi_Flags & HIF_DMOTION))
  142.   {
  143.     INPUTS = 1;
  144.   }
  145.   else
  146.   {
  147.     INPUTS = 5;
  148.   }
  149.  
  150.   if(GetVar("ENV:AHItoccataNoTask", prefs, sizeof prefs, NULL ) != -1)
  151.   {
  152.     if(prefs[0] == '1')
  153.     {
  154.       NoTask = TRUE;
  155.     }
  156.   }
  157.  
  158.   if(GetVar("ENV:AHItoccataIrqSize", prefs, sizeof prefs, NULL ) != -1)
  159.   {
  160.     if(StrToLong(prefs, &IrqSize) != -1)
  161.     {
  162.       IrqSize = max(IrqSize, 32);
  163.       IrqSize = min(IrqSize, 512);
  164.       switch(IrqSize) {
  165.         case 32:
  166.         case 64:
  167.         case 128:
  168.         case 256:
  169.         case 512:
  170.           break;
  171.         default:
  172.           IrqSize = 512;
  173.           break;
  174.       }
  175.     }
  176.   }
  177.  
  178.   return 0;
  179. }
  180.  
  181. void __saveds __asm __UserLibCleanup (register __a6 struct Library *libbase)
  182. {
  183.   if(DOSBase)       { CloseLibrary((struct Library *)DOSBase); DOSBase = NULL; }
  184.   if(UtilityBase)   { CloseLibrary(UtilityBase); UtilityBase = NULL; }
  185.   if(ToccataBase)   { CloseLibrary((struct Library *)ToccataBase); ToccataBase = NULL; }
  186. }
  187.  
  188. ULONG __asm __saveds intAHIsub_AllocAudio(
  189.     register __a1 struct TagItem *tagList,
  190.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  191. {
  192.   if((ToccataBase == NULL) ||
  193.      (ToccataBase->tb_HardInfo == NULL))
  194.   {
  195.     return AHISF_ERROR;
  196.   }
  197.  
  198.   // Make sure only there is only one user!
  199.   
  200.   Forbid();
  201.   if(In_Use)
  202.   {
  203.     Permit();
  204.     return AHISF_ERROR;
  205.   }
  206.   In_Use = TRUE;
  207.   Permit();
  208.  
  209.   if(AudioCtrl->ahiac_DriverData = AllocVec(sizeof(struct toccata),MEMF_PUBLIC|MEMF_ANY|MEMF_CLEAR))
  210.   {
  211.     dd->t_AHIsubBase    = AHIsubBase;
  212.     dd->t_NoTask        = NoTask;
  213.     dd->t_SlaveSignal   = -1;
  214.     dd->t_PlaySignal    = -1;
  215.     dd->t_RecordSignal  = -1;
  216.     dd->t_MixSignal     = -1;
  217.  
  218.     dd->t_MasterTask = FindTask(NULL);
  219.     dd->t_MasterSignal = AllocSignal(-1);
  220.     if(dd->t_MasterSignal != -1)
  221.     {
  222.       AudioCtrl->ahiac_MixFreq = T_FindFrequency(AudioCtrl->ahiac_MixFreq);
  223.  
  224.       Forbid();
  225.       if(dd->t_SlaveProcess = CreateNewProcTags(
  226.           NP_Entry,&SlaveProcessEntry,
  227.           NP_Name,_LibName,
  228.           NP_Priority,127,
  229.           TAG_DONE))
  230.       {
  231.         dd->t_SlaveProcess->pr_Task.tc_UserData = AudioCtrl;
  232.       }
  233.       Permit();
  234.  
  235.       if(dd->t_SlaveProcess)
  236.       {
  237.         Wait(1L << dd->t_MasterSignal);   // Wait for slave to come alive
  238.         if(dd->t_SlaveProcess != NULL)    // Is slave alive or dead?
  239.         {
  240.           dd->t_Flags |= TF_IAMTHEOWNER;
  241.  
  242.           return AHISF_KNOWSTEREO|AHISF_KNOWHIFI|AHISF_CANRECORD|
  243.                  AHISF_MIXING|AHISF_TIMING;
  244.         }
  245.       }
  246.     }
  247.   }
  248.  
  249.   In_Use = FALSE;
  250.   return AHISF_ERROR;
  251. }
  252.  
  253. void __asm __saveds intAHIsub_FreeAudio(
  254.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  255. {
  256.   if(AudioCtrl->ahiac_DriverData)
  257.   {
  258.     if(dd->t_SlaveProcess)
  259.     {
  260.       if(dd->t_SlaveSignal != -1)
  261.       {
  262.         Signal((struct Task *)dd->t_SlaveProcess,1L<<dd->t_SlaveSignal); // Kill him!
  263.       }
  264.       Wait(1L<<dd->t_MasterSignal);  // Wait for slave to die
  265.     }
  266.  
  267.     if(dd->t_Flags & TF_IAMTHEOWNER)
  268.     {
  269.       In_Use = FALSE;
  270.     }
  271.  
  272.     FreeSignal(dd->t_MasterSignal);
  273.     FreeVec(AudioCtrl->ahiac_DriverData);
  274.     AudioCtrl->ahiac_DriverData = NULL;
  275.   }
  276. }
  277.  
  278.  
  279.  
  280. ULONG __asm __saveds intAHIsub_Start(
  281.     register __d0 ULONG Flags,
  282.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  283. {
  284.  
  285.   AHIsub_Stop(AHISF_PLAY|AHISF_RECORD,AudioCtrl);       // Only half duplex!
  286.  
  287.   if(Flags & AHISF_PLAY)
  288.   {
  289.  
  290.     if(!(dd->t_PlaySoftInt = AllocVec(sizeof(struct Interrupt),MEMF_PUBLIC|MEMF_ANY|MEMF_CLEAR)))
  291.       return AHIE_NOMEM;
  292.  
  293.     if(!(dd->t_MixSoftInt = AllocVec(sizeof(struct Interrupt),MEMF_PUBLIC|MEMF_ANY|MEMF_CLEAR)))
  294.       return AHIE_NOMEM;
  295.  
  296.     switch(AudioCtrl->ahiac_BuffType)
  297.     {
  298.       case AHIST_M16S:
  299.         dd->t_PlaySoftInt->is_Code = (void (* )())PlayFuncMono;
  300.         dd->t_Mode = TMODE_LINEAR_16;
  301.         dd->t_TocSamples = PLAYBUFFERSIZE>>1;   // Toc. buffer is 16 bit mono
  302.         break;
  303.       case AHIST_S16S:
  304.         dd->t_PlaySoftInt->is_Code = (void (* )())PlayFuncStereo;
  305.         dd->t_Mode = TMODE_LINEAR_16_S;
  306.         dd->t_TocSamples = PLAYBUFFERSIZE>>2;   // Toc. buffer is 16 bit stereo
  307.         break;
  308.       case AHIST_M32S:
  309.         dd->t_PlaySoftInt->is_Code = (void (* )())PlayFuncMono32;
  310.         dd->t_Mode = TMODE_LINEAR_16;
  311.         dd->t_TocSamples = PLAYBUFFERSIZE>>1;   // Toc. buffer is 16 bit mono
  312.         break;
  313.       case AHIST_S32S:
  314.         dd->t_PlaySoftInt->is_Code = (void (* )())PlayFuncStereo32;
  315.         dd->t_Mode = TMODE_LINEAR_16_S;
  316.         dd->t_TocSamples = PLAYBUFFERSIZE>>2;   // Toc. buffer is 16 bit stereo
  317.         break;
  318.       default:
  319.         return AHIE_BADSAMPLETYPE;
  320.     }
  321.  
  322.     if(!(dd->t_SampBuffer1 = AllocVec(PLAYBUFFERSIZE,
  323.         MEMF_PUBLIC|MEMF_CLEAR|MEMF_ANY)))
  324.       return AHIE_NOMEM;
  325.     if(!(dd->t_SampBuffer2 = AllocVec(PLAYBUFFERSIZE,
  326.         MEMF_PUBLIC|MEMF_CLEAR|MEMF_ANY)))
  327.       return AHIE_NOMEM;
  328.  
  329.     if(!(dd->t_MixBuffer1 = AllocVec(AudioCtrl->ahiac_BuffSize,
  330.         MEMF_PUBLIC|MEMF_CLEAR|MEMF_ANY)))
  331.       return AHIE_NOMEM;
  332.     if(!(dd->t_MixBuffer2 = AllocVec(AudioCtrl->ahiac_BuffSize,
  333.         MEMF_PUBLIC|MEMF_CLEAR|MEMF_ANY)))
  334.       return AHIE_NOMEM;
  335.     if(!(dd->t_MixBuffer3 = AllocVec(AudioCtrl->ahiac_BuffSize,
  336.         MEMF_PUBLIC|MEMF_CLEAR|MEMF_ANY)))
  337.       return AHIE_NOMEM;
  338.  
  339.     dd->t_PlaySoftInt->is_Node.ln_Type = NT_INTERRUPT;
  340.     dd->t_PlaySoftInt->is_Node.ln_Name = _LibName;
  341.     dd->t_PlaySoftInt->is_Data = AudioCtrl;
  342.  
  343.     dd->t_MixSoftInt->is_Code = (void (* )())MixFunc;
  344.     dd->t_MixSoftInt->is_Node.ln_Type = NT_INTERRUPT;
  345.     dd->t_MixSoftInt->is_Node.ln_Name = _LibName;
  346.     dd->t_MixSoftInt->is_Data = AudioCtrl;
  347.  
  348.     Signal((struct Task *)dd->t_SlaveProcess,1L<<dd->t_PlaySignal);
  349.   }
  350.  
  351.   if(Flags & AHISF_RECORD)
  352.   {
  353.     if(!(dd->t_RecBuffer = AllocVec(RECBUFFERSIZE,MEMF_PUBLIC|MEMF_ANY)))
  354.       return AHIE_NOMEM;
  355.     if(!(dd->t_RecMessage = AllocVec(sizeof(struct AHIRecordMessage),MEMF_PUBLIC|MEMF_ANY|MEMF_CLEAR)))
  356.       return AHIE_NOMEM;
  357.  
  358.     dd->t_RecMessage->ahirm_Type = AHIST_S16S;
  359.     dd->t_RecMessage->ahirm_Buffer = dd->t_RecBuffer;
  360.  
  361.     Signal((struct Task *)dd->t_SlaveProcess,1L<<dd->t_RecordSignal);
  362.   }
  363.  
  364.   return AHIE_OK;
  365. }
  366.  
  367. /*
  368. void __asm __saveds __interrupt intAHIsub_Update(
  369.     register __d0 ULONG Flags,
  370.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  371. {
  372. }
  373. */
  374.  
  375. void __asm __saveds intAHIsub_Stop(
  376.     register __d0 ULONG Flags,
  377.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  378. {
  379.   if(Flags & AHISF_PLAY)
  380.   {
  381.     T_Stop(TSF_DONTSAVECACHE);
  382.     dd->t_Flags &= ~TF_ISPLAYING;
  383.  
  384. // Disable Loopback
  385.     T_SetPartTags(PAT_LoopbackVolume, -64, TAG_DONE);
  386.  
  387.     FreeVec(dd->t_MixBuffer1);    dd->t_MixBuffer1  = NULL;
  388.     FreeVec(dd->t_MixBuffer2);    dd->t_MixBuffer2  = NULL;
  389.     FreeVec(dd->t_MixBuffer3);    dd->t_MixBuffer3  = NULL;
  390.     FreeVec(dd->t_SampBuffer1);   dd->t_SampBuffer1 = NULL;
  391.     FreeVec(dd->t_SampBuffer2);   dd->t_SampBuffer2 = NULL;
  392.     FreeVec(dd->t_MixSoftInt);    dd->t_MixSoftInt  = NULL;
  393.     FreeVec(dd->t_PlaySoftInt);   dd->t_PlaySoftInt = NULL;
  394.   }
  395.  
  396.   if(Flags & AHISF_RECORD)
  397.   {
  398.     T_Stop(TSF_DONTSAVECACHE);
  399.     dd->t_Flags &= ~TF_ISRECORDING;
  400.  
  401. // Disable Loopback
  402.     T_SetPartTags(PAT_LoopbackVolume, -64, TAG_DONE);
  403.  
  404.     FreeVec(dd->t_RecBuffer);
  405.     dd->t_RecBuffer = NULL;
  406.   }
  407. }
  408.  
  409.  
  410.  
  411. LONG __asm __saveds intAHIsub_GetAttr(
  412.     register __d0 ULONG Attribute,
  413.     register __d1 LONG Argument,
  414.     register __d2 LONG Default,
  415.     register __a1 struct TagItem *tagList,
  416.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl)
  417. {
  418.   if(ToccataBase == NULL)
  419.   {
  420.     return Default;
  421.   }
  422.  
  423.   switch(Attribute)
  424.   {
  425.     case AHIDB_Bits:
  426.       return 16;
  427.     case AHIDB_Frequencies:
  428.     {
  429.       ULONG freq = NULL;
  430.       LONG  freqs = 0;
  431.       while(freq = T_NextFrequency(freq))
  432.         freqs++;
  433.       return freqs;
  434.     }
  435.     case AHIDB_Frequency: // Index->Frequency
  436.     {
  437.       ULONG freq = NULL;
  438.       LONG  i;
  439.       for(i = 0; i<=Argument ; i++)
  440.         freq = T_NextFrequency(freq);
  441.       return (LONG) freq;
  442.     }
  443.     case AHIDB_Index: // Frequency->Index
  444.     {
  445.       ULONG freq = NULL,realfreq = T_FindFrequency(Argument);
  446.       LONG  index = 0;
  447.       while((freq = T_NextFrequency(freq)) != realfreq)
  448.         index++;
  449.       return index;
  450.     }
  451.     case AHIDB_Author:
  452.       return (LONG) "Martin 'Leviticus' Blom";
  453.     case AHIDB_Copyright:
  454.       return (LONG) "Public Domain";
  455.     case AHIDB_Version:
  456.       return (LONG) _LibID;
  457.     case AHIDB_Annotation:
  458.       return (LONG) "Based on code by Pauli Porkka, Peter Kunath and Frank Riffel.";
  459.     case AHIDB_Record:
  460.       return TRUE;
  461.     case AHIDB_FullDuplex:
  462.       return FALSE;
  463.     case AHIDB_Realtime:
  464.         return TRUE;
  465.     case AHIDB_MaxPlaySamples:
  466.       return Default+PLAYBUFFERSIZE;
  467.     case AHIDB_MaxRecordSamples:
  468.       return RECBUFFERSIZE>>2;
  469.     case AHIDB_MinMonitorVolume:
  470.       return 0x00000;
  471.     case AHIDB_MaxMonitorVolume:
  472.       if(ToccataBase->tb_HardInfo->hi_Flags & HIF_1845)
  473.       {
  474.         return 0x0000; // Workaround for bug in AD1845
  475.       }
  476.       else
  477.       {
  478.         return 0x10000;
  479.       }
  480.     case AHIDB_MinInputGain:
  481.       return 0x10000;
  482.     case AHIDB_MaxInputGain:
  483.       return 0xd55d0;           // 13.335<<16 == +22.5 dB
  484.     case AHIDB_MinOutputVolume:
  485.       return 0x00000;
  486.     case AHIDB_MaxOutputVolume:
  487.       return 0x10000;
  488.     case AHIDB_Inputs:
  489.       return INPUTS;
  490.     case AHIDB_Input:
  491.       return (LONG) Inputs[Argument];
  492.     case AHIDB_Outputs:
  493.       return 1;
  494.     case AHIDB_Output:
  495.       return (LONG) "Line";     // We have only one output!
  496.     default:
  497.       return Default;
  498.   }
  499. }
  500.  
  501. const static LONG negboundaries[] =
  502. {
  503.   65536,55141,46395,39037,32845,27636,23253,19565,16461,13850,11654,9805,8250,
  504.   6941,5840,4914,4135,3479,2927,2463,2072,1743,1467,1234,1038,873,735,618,520,
  505.   438,368,310,260,219,184,155,130,110,92,77,65,55,46,39,32,27,23,19,16,13,11,9,
  506.   8,6,5,4,4,3,2,2,2,1,1,1,0
  507. };
  508.  
  509. LONG fixed2negdbvalue( LONG volume)
  510. {
  511.   LONG i = 0;
  512.  
  513.   while(volume < negboundaries[i])
  514.     i++;
  515.   return(-i);
  516. }
  517.  
  518. const static LONG posboundaries[] =
  519. {
  520.   65536,77889,92572,110022,130761,155410,184705,219522,260903,
  521.   310084,368536,438005,520570,618699,735326,873936
  522. };
  523.  
  524. LONG fixed2posdbvalue( LONG volume)
  525. {
  526.   LONG i = 0;
  527.  
  528.   while((volume >= posboundaries[i+1]) && i<=14)
  529.     i++;
  530.   return(i);
  531. }
  532.  
  533. LONG __asm __saveds __interrupt intAHIsub_HardwareControl(
  534.     register __d0 ULONG attribute,
  535.     register __d1 LONG argument,
  536.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  537. {
  538.   LONG rc = TRUE;
  539.  
  540.   if(ToccataBase && ToccataBase->tb_HardInfo)   // Check if hardware is present...
  541.   {
  542.     switch (attribute)
  543.     {
  544.       case AHIC_MonitorVolume:
  545.         if((ToccataBase->tb_HardInfo->hi_Flags & HIF_1845) == 0)
  546.         {
  547.           dd->t_Loopback = argument;
  548.           if(dd->t_Flags & TF_ISRECORDING)
  549.           {
  550.             T_SetPartTags(PAT_LoopbackVolume, fixed2negdbvalue(argument), TAG_DONE);
  551.           }
  552.         }
  553.         break;
  554.       case AHIC_MonitorVolume_Query:
  555.         if(dd->t_Flags & TF_ISRECORDING)
  556.         {
  557.           T_GetPartTags(PAT_LoopbackVolume, &rc, TAG_DONE);
  558.           rc = negboundaries[-rc];
  559.         }
  560.         else
  561.         {
  562.           rc = dd->t_Loopback;
  563.         }
  564.         break;
  565.       case AHIC_InputGain:
  566.         T_SetPartTags(PAT_InputVolumeLeft, fixed2posdbvalue(argument),
  567.                       PAT_InputVolumeRight, fixed2posdbvalue(argument), TAG_DONE);
  568.         break;
  569.       case AHIC_InputGain_Query:
  570.         T_GetPartTags(PAT_InputVolumeLeft, &rc, TAG_DONE);
  571.         rc = negboundaries[rc];
  572.         break;
  573.       case AHIC_OutputVolume:
  574.         T_SetPartTags(PAT_OutputVolumeLeft, fixed2negdbvalue(argument),
  575.                       PAT_OutputVolumeRight, fixed2negdbvalue(argument), TAG_DONE);
  576.         break;
  577.       case AHIC_OutputVolume_Query:
  578.         T_GetPartTags(PAT_OutputVolumeLeft, &rc, TAG_DONE);
  579.         rc = negboundaries[-rc];
  580.         break;
  581.       case AHIC_Input:
  582.         dd->t_Input = argument;
  583.         T_SetPartTags(PAT_Input,   inputmap[argument],
  584.                       PAT_MicGain, micgainmap[argument], TAG_DONE);
  585.         break;
  586.       case AHIC_Input_Query:
  587.         rc = dd->t_Input;
  588.         break;
  589.       case AHIC_Output_Query:
  590.         rc = 0;                           // There is only one output
  591.         break;
  592.       default:
  593.         rc = FALSE;
  594.         break;
  595.     }
  596.   }
  597.   else
  598.   {
  599.     rc = FALSE;
  600.   }
  601.   return rc;
  602. }
  603.  
  604. // SlaveProcessEntry() sets up a2 and a6. __saveds fixes a5
  605. void __asm __saveds SlaveProcess(register __a2 struct AHIAudioCtrlDrv *AudioCtrl)
  606. {
  607.   struct Process *me = (struct Process *) FindTask(NULL);
  608.  
  609.   T_SaveSettings(0);                 // Save state
  610.  
  611.   T_Stop(TSF_DONTSAVECACHE);
  612.   dd->t_Flags &= ~(TF_ISPLAYING | TF_ISRECORDING);
  613.  
  614.   T_SetPartTags(                     // Reset
  615.       PAT_InputVolumeLeft,    0,
  616.       PAT_InputVolumeRight,   0,
  617.       PAT_OutputVolumeLeft,   0,
  618.       PAT_OutputVolumeRight,  0,
  619.       PAT_LoopbackVolume,     -64,
  620.       PAT_Input,              TINPUT_Line,
  621. //      PAT_Mode,               TMODE_LINEAR_16_S,
  622. //      PAT_Frequency,          AudioCtrl->ahiac_MixFreq,
  623.       TAG_DONE);
  624.  
  625.   dd->t_SlaveSignal  = AllocSignal(-1);
  626.   dd->t_PlaySignal   = AllocSignal(-1);
  627.   dd->t_RecordSignal = AllocSignal(-1);
  628.   dd->t_MixSignal    = AllocSignal(-1);
  629.  
  630.   if( (dd->t_SlaveSignal  != -1) &&
  631.       (dd->t_PlaySignal   != -1) &&
  632.       (dd->t_RecordSignal != -1) &&
  633.       (dd->t_MixSignal    != -1))
  634.   {
  635.     // Tell Master we're alive
  636.     Signal(dd->t_MasterTask, 1L << dd->t_MasterSignal);
  637.  
  638.     for(;;)
  639.     {
  640.       ULONG signalset;
  641.     
  642.       signalset = Wait((1L << dd->t_SlaveSignal)
  643.                      | (1L << dd->t_PlaySignal)
  644.                      | (1L << dd->t_RecordSignal)
  645.                      | (1L << dd->t_MixSignal));
  646.  
  647.       if(signalset & (1L << dd->t_SlaveSignal))
  648.       {
  649.         // Quit
  650.         break;
  651.       }
  652.  
  653.       if(signalset & (1L << dd->t_PlaySignal))
  654.       {
  655.         StartPlaying(AudioCtrl, me);
  656.       }
  657.  
  658.       if(signalset & (1L << dd->t_RecordSignal))
  659.       {
  660.         StartRecording(AudioCtrl, me);
  661.       }
  662.  
  663.       if(signalset & (1L << dd->t_MixSignal))
  664.       {
  665.         CallHookPkt(AudioCtrl->ahiac_PlayerFunc, AudioCtrl, NULL);
  666.         if(! ((*AudioCtrl->ahiac_PreTimer)()) ) {
  667.           CallHookPkt(AudioCtrl->ahiac_MixerFunc, AudioCtrl, dd->t_MixBuffer3);
  668.         }
  669.         (*AudioCtrl->ahiac_PostTimer)();
  670.       }
  671.     }
  672.   }
  673.  
  674.   T_Stop(TSF_DONTSAVECACHE);
  675.   dd->t_Flags &= ~(TF_ISPLAYING | TF_ISRECORDING);
  676.  
  677.   T_LoadSettings(0);                 // Restore state
  678.  
  679.   Forbid();
  680.   FreeSignal(dd->t_SlaveSignal);    dd->t_SlaveSignal   = -1;
  681.   FreeSignal(dd->t_PlaySignal);     dd->t_PlaySignal    = -1;
  682.   FreeSignal(dd->t_RecordSignal);   dd->t_RecordSignal  = -1;
  683.   FreeSignal(dd->t_MixSignal);      dd->t_MixSignal     = -1;
  684.  
  685.   // Tell the Master we're dying
  686.   dd->t_SlaveProcess = NULL;
  687.   Signal((struct Task *)dd->t_MasterTask, 1L << dd->t_MasterSignal);
  688.  
  689.   // Multitaking will resume when we are dead.
  690. }
  691.  
  692.  
  693. BOOL StartPlaying(struct AHIAudioCtrlDrv *AudioCtrl, struct Process *me)
  694. {
  695.   BOOL playing;
  696.  
  697.   // Disable Loopback
  698.   T_SetPartTags(PAT_LoopbackVolume, -64, TAG_DONE);
  699.  
  700.   playing = T_RawPlaybackTags(
  701.       TT_ErrorTask,   me,
  702.       TT_ErrorMask,   (1L << dd->t_PlaySignal),
  703.       TT_RawInt,      dd->t_PlaySoftInt,
  704.       TT_Mode,        dd->t_Mode,
  705.       TT_Frequency,   AudioCtrl->ahiac_MixFreq,
  706.       TT_RawBuffer1,  dd->t_SampBuffer1,
  707.       TT_RawBuffer2,  dd->t_SampBuffer2,
  708.       TT_BufferSize,  PLAYBUFFERSIZE,
  709.       TT_RawIrqSize,  IrqSize,
  710.       TAG_DONE);
  711.   
  712.   if(playing)
  713.   {
  714.     dd->t_Flags |= TF_ISPLAYING;
  715.   }
  716.  
  717.   return playing;
  718. }
  719.  
  720. BOOL StartRecording(struct AHIAudioCtrlDrv *AudioCtrl, struct Process *me)
  721. {
  722.   BOOL recording;
  723.  
  724.   if(ToccataBase->tb_HardInfo->hi_Flags & HIF_1845)
  725.   {
  726.     // Disable Loopback (workaround for bug in AD1845)
  727.     T_SetPartTags(PAT_LoopbackVolume, -64, TAG_DONE);
  728.   }
  729.   else 
  730.   {
  731.     // Enable Loopback
  732.     T_SetPartTags(PAT_LoopbackVolume, fixed2negdbvalue(dd->t_Loopback), TAG_DONE);
  733.   }
  734.  
  735.   recording = T_CaptureTags(
  736.       TT_ErrorTask,   me,
  737.       TT_ErrorMask,   (1L << dd->t_RecordSignal),
  738.       TT_Save,        RecordFunc,
  739.       TT_CBParamA1,   AudioCtrl,
  740.       TT_Mode,        TMODE_LINEAR_16_S,
  741.       TT_Frequency,   AudioCtrl->ahiac_MixFreq,
  742.       TT_BufferSize,  RECBUFFERSIZE,
  743.       TT_Flags,       TTF_READYRETURN,
  744.       TAG_DONE);
  745.  
  746.   if(recording)
  747.   {
  748.     dd->t_Flags |= TF_ISRECORDING;
  749.   }
  750.  
  751.   return recording;
  752. }
  753.